package services

import (
	"encoding/json"
	"fmt"
	"strings"

	"jlpay-sdk-go/pkg/jlpay/core"
	"jlpay-sdk-go/pkg/jlpay/models"
)

// BaseService 服务基类
type BaseService struct {
	config       *core.Config
	httpClient   core.HttpClient
	signVerifier core.SignVerifier
	cryptoSvc    core.CryptoService
}

// NewBaseService 创建服务基类
func NewBaseService(config *core.Config) *BaseService {
	return &BaseService{
		config:       config,
		httpClient:   core.NewDefaultHttpClient(config.ConnectTimeout, config.ReadTimeout),
		signVerifier: core.NewDefaultSignVerifier(config),
		cryptoSvc:    core.NewDefaultCryptoService(config),
	}
}

// Post 发送POST请求
func (s *BaseService) Post(request interface{}, responseClass interface{}, apiPath string) error {
	return s.execute("POST", request, responseClass, apiPath)
}

// Get 发送GET请求
func (s *BaseService) Get(request interface{}, responseClass interface{}, apiPath string) error {
	return s.execute("GET", request, responseClass, apiPath)
}

// execute 执行HTTP请求
func (s *BaseService) execute(method string, request interface{}, responseClass interface{}, apiPath string) error {
	// 校验请求参数
	if checker, ok := request.(interface{ CheckRequiredParams(*core.Config) error }); ok {
		if err := checker.CheckRequiredParams(s.config); err != nil {
			return fmt.Errorf("参数校验失败: %w", err)
		}
	}

	// 构建完整URL
	url := s.config.BaseURL + apiPath

	// 获取URI
	uri := apiPath
	if strings.HasPrefix(apiPath, "http") {
		if parts := strings.SplitN(apiPath, "//", 2); len(parts) > 1 {
			if parts := strings.SplitN(parts[1], "/", 2); len(parts) > 1 {
				uri = "/" + parts[1]
			}
		}
	}

	// 处理请求加密
	cryptoHeaders := make(map[string]string)
	if err := s.handleEncrypt(request, cryptoHeaders); err != nil {
		return fmt.Errorf("处理请求加密失败: %w", err)
	}

	// 将请求对象转换为map
	var body map[string]interface{}

	// 首先尝试通过RawMapGetter接口获取原始请求映射
	if rawMapGetter, ok := request.(models.RawMapGetter); ok {
		if rawMap, exist := rawMapGetter.GetRawMap(); exist && len(rawMap) > 0 {
			body = rawMap
		} else {
			// 如果没有原始映射，使用通用方法转换
			var err error
			body, err = mapRequestObject(request)
			if err != nil {
				return fmt.Errorf("转换请求为map失败: %w", err)
			}
		}
	} else if mapper, ok := request.(interface {
		ToMap() (map[string]interface{}, error)
	}); ok {
		// 尝试使用ToMap方法
		var err error
		body, err = mapper.ToMap()
		if err != nil {
			return fmt.Errorf("转换请求为map失败: %w", err)
		}
	} else {
		// 尝试JSON序列化然后反序列化为map
		data, err := json.Marshal(request)
		if err != nil {
			return fmt.Errorf("序列化请求失败: %w", err)
		}

		if err := json.Unmarshal(data, &body); err != nil {
			return fmt.Errorf("反序列化请求失败: %w", err)
		}
	}

	// 签名
	sign, timestamp, nonce, err := s.signVerifier.Sign(method, uri, body)
	if err != nil {
		return fmt.Errorf("签名失败: %w", err)
	}

	// 构建HTTP请求
	headers := map[string]string{
		"Content-Type":      "application/json; charset=utf-8",
		"x-jlpay-appid":     s.config.AppID,
		"x-jlpay-nonce":     nonce,
		"x-jlpay-timestamp": timestamp,
		"x-jlpay-sign-alg":  "SM3WithSM2WithDer",
		"x-jlpay-sign":      sign,
	}

	// 添加必需的请求头 - 根据Python SDK逻辑
	// 从请求数据中提取商户号
	if merchNo, ok := body["merch_no"].(string); ok && merchNo != "" {
		headers["x-jlpay-merchno"] = merchNo
	} else if mchID, ok := body["mch_id"].(string); ok && mchID != "" {
		headers["x-jlpay-merchno"] = mchID
	}

	// 从请求数据中提取机构号
	if orgNo, ok := body["org_no"].(string); ok && orgNo != "" {
		headers["x-jlpay-orgno"] = orgNo
	}

	// 添加加密相关的请求头
	for key, value := range cryptoHeaders {
		headers[key] = value
	}

	httpRequest := &core.HttpRequest{
		URL:     url,
		Method:  method,
		Headers: headers,
		Body:    body,
	}

	// 执行请求
	httpResponse, err := s.httpClient.Execute(httpRequest)
	if err != nil {
		return fmt.Errorf("执行HTTP请求失败: %w", err)
	}

	// 验证响应签名
	if signature, ok := httpResponse.Headers["x-jlpay-sign"]; ok {
		var responseBody map[string]interface{}
		if err := json.Unmarshal([]byte(httpResponse.Body), &responseBody); err != nil {
			return fmt.Errorf("解析响应体失败: %w", err)
		}

		if err := s.signVerifier.Verify(
			method,
			uri,
			httpResponse.Headers["x-jlpay-timestamp"],
			httpResponse.Headers["x-jlpay-nonce"],
			responseBody,
			signature,
		); err != nil {
			return fmt.Errorf("验证响应签名失败: %w", err)
		}
	}

	// 解析响应
	var responseData map[string]interface{}
	if err := json.Unmarshal([]byte(httpResponse.Body), &responseData); err != nil {
		return fmt.Errorf("解析响应JSON失败: %w", err)
	}

	// 将响应数据映射到响应对象
	if err := models.ParseResponse(responseData, responseClass); err != nil {
		return fmt.Errorf("解析响应对象失败: %w", err)
	}

	// 处理响应解密（在解析之后进行，确保解密后的值不会被覆盖）
	if err := s.handleDecrypt(responseClass, httpResponse.Headers); err != nil {
		return fmt.Errorf("处理响应解密失败: %w", err)
	}

	return nil
}

// mapRequestObject 将请求对象转换为map
func mapRequestObject(req interface{}) (map[string]interface{}, error) {
	data, err := json.Marshal(req)
	if err != nil {
		return nil, err
	}

	var result map[string]interface{}
	if err := json.Unmarshal(data, &result); err != nil {
		return nil, err
	}

	return result, nil
}

// handleEncrypt 处理请求加密
func (s *BaseService) handleEncrypt(request interface{}, headers map[string]string) error {
	cryptoHeaders, err := s.cryptoSvc.EncryptRequest(request)
	if err != nil {
		return err
	}

	for key, value := range cryptoHeaders {
		headers[key] = value
	}

	return nil
}

// handleDecrypt 处理响应解密
func (s *BaseService) handleDecrypt(response interface{}, headers map[string]string) error {
	return s.cryptoSvc.DecryptResponse(response, headers)
}
